// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: tianqiang

#include "coin2/exchange/mexc/api_order_v3/native_rest_async_asio_subscriber.h"

namespace coin2::exchange::mexc::api_order_v3 {

void MexcRestAsyncAsioSubscriber::QueryBalance() {
  auto http_context = rest_client()->QueryAccountBalance();
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void MexcRestAsyncAsioSubscriber::QueryOpenOrders(const std::string& native_symbol) {
  RestParams params;
  params.set_symbol(native_symbol);
  auto http_context = rest_client()->QueryOpenOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void MexcRestAsyncAsioSubscriber::QueryAllOrders(const std::string& native_symbol) {
  RestParams params;
  params.set_symbol(native_symbol);
  auto http_context = rest_client()->QueryAllOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void MexcRestAsyncAsioSubscriber::QueryFillOrders(const std::string& native_symbol) {
  RestParams params;
  params.set_symbol(native_symbol);
  auto http_context = rest_client()->QueryFillOrders(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void MexcRestAsyncAsioSubscriber::QueryTransfer() {
  RestParams params;
  auto http_context = rest_client()->QueryDeposit(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);

  http_context = rest_client()->QueryWithdrawal(params);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);

  const static std::vector<std::string> account_type = {"SPOT", "FUTURES"};
  for (const auto& from_account_type : account_type) {
    for (const auto& to_account_type : account_type) {
      params.set_from_account_type(from_account_type);
      params.set_to_account_type(to_account_type);
      http_context = rest_client()->QueryTransfer(params);
      if (!http_context) {
        return;
      }
      http_context->handler =
          std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
      http_driver_->PostAsyncContext(http_context);
    }
  }
}

void MexcRestAsyncAsioSubscriber::GenListenKey(bool is_init) {
  auto http_context = rest_client()->GenListenKey(is_init);
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void MexcRestAsyncAsioSubscriber::ExtendListenKey() {
  auto http_context = rest_client()->ExtendListenKey();
  if (!http_context) {
    return;
  }
  http_context->handler =
      std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

// void MexcRestAsyncAsioSubscriber::QueryOrdersByIds(
//     const std::string& exchange_order_ids,
//     const std::string& proc_order_ids) {
//   int64_t ts = GetCurrentTimestamp();
//   if (ts - last_query_order_by_ids_ts_ < 5'000'000'000LL) {
//     SPDLOG_WARN("query orders by ids too often!!");
//     return;
//   }

//   RestParams params;
//   params.set_order_id(exchange_order_ids);
//   params.set_client_order_id(proc_order_ids);
//   auto http_context = rest_client()->QueryOrdersByIds(params);
//   if (!http_context) {
//     return;
//   }
//   http_context->handler =
//       std::bind(&MexcRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
//   http_driver_->PostAsyncContext(http_context);
//   last_query_order_by_ids_ts_ = ts;
// }

void MexcRestAsyncAsioSubscriber::SubscribeAsync() {
  AddPeriodicTask(
      std::bind(&MexcRestAsyncAsioSubscriber::GenListenKey, this, true),
      5,
      "init_gen_listen_key");

  AddPeriodicTask(
      std::bind(&MexcRestAsyncAsioSubscriber::ExtendListenKey, this),
      1200,
      "extend_listen_key",
      300);

  AddPeriodicTask(
      std::bind(&MexcRestAsyncAsioSubscriber::QueryBalance, this),
      config_.query_account_balance_period_sec(),
      "query_balance");

  if (is_readonly_order_system_ && symcache_->is_spot()) {
    AddPeriodicTask(
        std::bind(&MexcRestAsyncAsioSubscriber::QueryTransfer, this),
        config_.query_account_balance_period_sec(),
        "query_transfer");
  }

  auto symbol_list = native_symbols();

  AddPeriodicTask(
      std::bind(&MexcRestAsyncAsioSubscriber::QueryOpenOrders, this, std::placeholders::_1),
      config_.query_open_orders_period_sec(),
      "query_open_orders",
      symbol_list);

  AddPeriodicTask(
      std::bind(&MexcRestAsyncAsioSubscriber::QueryAllOrders, this, std::placeholders::_1),
      config_.query_cancel_orders_period_sec(),
      "query_all_orders",
      symbol_list);

  AddPeriodicTask(
      std::bind(&MexcRestAsyncAsioSubscriber::QueryFillOrders, this, std::placeholders::_1),
      config_.query_fill_period_sec(),
      "query_fill_orders",
      symbol_list);

  // mb_->Subscribe("mexc/query_orders_by_ids", [this](const std::string&, void* data) {
  //   std::string param = *(reinterpret_cast<std::string*>(data));
  //   std::vector<std::string> info;
  //   boost::split(info, param, boost::is_any_of("|"));
  //   if (info.size() != 2 || info[0].empty() || info[1].empty()) {
  //     LOG(ERROR) << "ignored check zombie orders, invalid info";
  //     return;
  //   }
  //   this->QueryOrdersByIds(info[0], info[1]);
  // });
}

}  // namespace coin2::exchange::mexc::api_order_v3
